PwdMgr: One Go Codebase for a Password Manager on Desktop, Mobile, and the Web
My passwords live in a KeePass file, and for years I opened that file with three different apps: KeeWeb on the desktop, Keepass2Android on my Android phone, and KeePassium on iOS. That works, but it never felt like one tool. This post is about the app I wrote to change that, PwdMgr, and about how far a single Go codebase, including the GUI, can go today.
Why another password manager? #
The trigger was KeeWeb. I like it, but the last regular release is 1.18.7 from July 2021. After almost five years of silence, two pre-releases appeared in spring 2026, without any explanation and with builds for Linux only. Users asked about the motivation, pointing out that, with today’s supply chain attacks, a surprise release of a password manager “seems a bit fishy”. The answer came months later: one maintainer is working on a larger update on their own, the release needs third-party credentials the other maintainer doesn’t have, and so only the Linux build could be published. That’s probably harmless, and I appreciate everyone keeping the project alive in their spare time. But “probably harmless” and “unclear who can publish a release” are not what I want to hear about the app that holds my passwords.
There’s also a deadline. The KeeWeb on my Apple Silicon Mac is the Intel build of 1.18.7, running through Rosetta, and Apple has announced that macOS 27 is the last version with full Rosetta support. From macOS 28 on, Intel-only apps won’t launch anymore. Yes, there is an arm64 build of 1.18.7, but that only buys time for a five-year-old Electron app.
The second reason is the gap between desktop and phone. KeeWeb is feature-rich, practical, and looks good. The mobile apps are more reduced: Keepass2Android does its job but feels dated, and KeePassium is fine for what I use it for on iOS. Every device felt a little different. And to be honest, I use maybe 20% of KeeWeb’s features. A new app is a chance to focus on exactly those, and to see where the journey goes once other people start asking for features.
What I don’t want to give up is KeePass as a concept: one encrypted file, no account, no dependency on a service. Commercial password managers solve the same problem with a subscription, and in my experience, the one feature I need is usually the one missing from the free plan.
The third reason was curiosity. I had used Gio in another project and wanted to know how far its cross-platform promise goes: Linux, macOS, Windows, Android, and iOS from one Go codebase, with no Electron, no Tauri, and no web view in between.
And finally, I simply enjoy this kind of work, and with AI coding assistants around, it was a good excuse to see how much one person can get done in their spare time.
One codebase, really #
PwdMgr’s tagline is “your passwords, your file”: it reads and writes standard KDBX files, so it works alongside KeePass, KeePassXC, and the mobile KeePass apps. There is no account, no server, no ads, and no tracking. The current version builds as a DMG for macOS (Apple Silicon and Intel), an executable for Windows, a tarball for Linux, an APK for Android, and an IPA for iOS. The same code also compiles to WebAssembly, so there is a version that runs in the browser without any installation. That one you can try right now: pwdmgr.gesellix.com/app. The downloads for the other platforms and the source code aren’t public yet, but that’s about to change: they will be published together, soon. The download section of the website already shows what will be offered.
The numbers are the part that surprised me most. Of about 70,000 lines of Go (without tests), about 5% live in platform-specific files. On top of that come about 1,300 lines of Java, Objective-C, C, and JavaScript for the few places where the app has to talk to the operating system directly. Everything else (the KeePass logic, the sync, the dialogs, the layout that adapts from a wide desktop window to a narrow phone screen) is shared.
Gio is an immediate-mode GUI toolkit: the UI is code, drawn every frame, without a widget tree in between. That takes some getting used to, but it is fast, also on mobile, and it makes the UI as testable as the rest of the code. Compared to KeeWeb, PwdMgr feels a bit snappier, which is no surprise without Electron in between. The store screenshots in this post come from a Go test that renders the app with a made-up database.
Gio is not huge, and its maintainers are open to contributions. Along the way, I needed a few things Gio didn’t have yet: the new UIScene life cycle that apps built with a recent iOS SDK require, a way to mark a copied password as sensitive so that clipboard managers and histories skip it, and events for when the app goes to the background on Android and iOS, which the auto-lock needs. Those patches are now part of Gio upstream, and so are two fixes for saving files on Android. I knew very little about window managers or the Android and iOS life cycles before. With an AI assistant at hand, reading the documentation and the toolkit’s code became much easier, and building a patch I could defend in a review was within reach.
Go itself helps with the security side, which matters for this particular kind of app. It is memory safe, and it gives you enough control to do the things a password manager should do: protected values stay encrypted in memory while a database is open, with the key in locked memory; the master password is wiped once the key is derived; new databases use Argon2id; copied passwords are cleared from the clipboard after a timeout; and on Android, the window is blocked from screenshots by default.
Not polished, but practical #
Let’s be honest: PwdMgr looks like what it is, an app a developer wrote for their own needs. The UI is plain, some dialogs say more than they need to, and the settings are organized by what they affect (“This database” vs. “App on this device”) rather than by what a designer would consider intuitive. It is a tool, not a product.
But it is a tool I use every day, and it covers what I need: browsing and searching entries (including an advanced search over protected fields and history), groups, tags, custom fields, a trash, expiry dates, a password generator, and a password health check that finds weak, reused, and old passwords and, only if you ask for it, checks them against Have I Been Pwned. The database can be synced through Google Drive, or directly between your own devices on the local network, without any cloud.
What I find more interesting than the feature list is how cheap improvements have become. In July, I compared PwdMgr feature by feature with KeeWeb. Back then, PwdMgr had no trash, no custom fields, no expiry dates, and no password audit. All of those exist now. Most of that happened in October, when I worked on the project with Claude Code, and the repository gained more than 500 commits in a single month. I also tried other assistants, ChatGPT and JetBrains’ Junie, for research, experiments, and alternative approaches, but in the end I always let Claude do the actual work. That deserves its own post.
The command line #
Since I was writing a KeePass app anyway, I wanted to see whether a command line interface makes sense. It does: the same binary that starts the GUI is also a CLI, sharing the same core. There are also small CLI-only binaries without the GUI for Linux, macOS, and Windows.
# search across all fields, values of protected fields stay hidden
pwdmgr search github -d vault.kdbx
# check password health, exit code 3 if something is found
pwdmgr health -d vault.kdbx --fail-on-findings
Every command can run non-interactively, with the password from a file or stdin, which makes it usable in scripts and containers.
Between the GUI and the CLI, there’s also a terminal UI: pwdmgr tui -d vault.kdbx opens the database full-screen in the terminal, with search as you type, entry details, and copying of fields.
It works over SSH too, copying through the terminal’s own clipboard, and it locks and clears the clipboard just like the app.
For now, the TUI only reads the database.
It will catch up with the GUI eventually: I’m a completionist, in games and in software.
I have an idea for where this could go: publishing artifacts from a CI pipeline, where a person enters a password interactively at the right moment, instead of keeping long-lived credentials in CI secrets.
That’s only an idea for now, not even a spike, but it’s one of the reasons the CLI exists.
What’s next #
Two big steps are next: opening the repository, and getting PwdMgr into the app stores. The stores turn out to be a project of their own, with listings, screenshots, and review notes in three languages for three stores: the iOS build already goes to TestFlight, the name is reserved in the Microsoft Store and the submission is prepared, and Google Play wants a closed test with at least 12 testers for 14 consecutive days before a new developer account may publish an app.
This is where I need your help. If you have an Android phone (Android 8 or newer) and a Google account, please join the closed test. Everything you need is on pwdmgr.gesellix.com/closed-test.html: send the address of the Google account you use in the Play Store, and once you’re on the list, the remaining steps take about two minutes. Then stay a tester for 14 days. You don’t need to store any real passwords: a test database with made-up entries is enough. And the app sends nothing unless you switch on one of its online features yourself, like the Google Drive sync or the check against known breaches.
Until the repository is public, questions, ideas, and bug reports are welcome through the contact address on the website. I plan to write about the store publishing experience, the CLI and CI idea, and working with AI coding assistants in separate posts. And if you’re curious how far Gio can take your own Go project: probably further than you think.